package top.ezzz.rpc.controller;


import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSON;
import com.google.protobuf.Message;
import io.grpc.solon.annotation.GrpcClient;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Body;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.core.handle.Result;
import top.ezzz.rpc.protobuf.AddressBookServiceGrpc;
import top.ezzz.rpc.protobuf.PersonProto;
import top.ezzz.rpc.server.AddressBookService;
import top.ezzz.rpc.util.GrpcMessageUtil;
import top.ezzz.rpc.util.MessageLemon;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Controller
public class GrpcController {

    @GrpcClient("demo-grpc")
    AddressBookServiceGrpc.AddressBookServiceBlockingStub blockingStub;

    @GrpcClient("demo-grpc")
    AddressBookServiceGrpc.AddressBookServiceStub asyncStub;


    /**
     * rpc 测试，rpc结果自动转化为 json
     *
     * @param name
     * @return
     */
    @Mapping("rpc/hello")
    public Result rpcHello(String name) {
        List<Map<String, Object>> result = new ArrayList<>();
        PersonProto.GetAddressBookRequest request = PersonProto.GetAddressBookRequest.newBuilder()
                .setOwner(name).build();
        PersonProto.AddressBook addressBook = blockingStub.getAddressBook(request);
        // JSON json = GrpcMessageUtil.toJson(addressBook);
        // Message message = GrpcMessageUtil.toMessage(json, PersonProto.AddressBook.class);
        // log.info("message:{}", message);
        return Result.succeed(addressBook);
    }


    /**
     * 借助参数解析器，直接将 json 转化为 protobuf 请求消息
     *
     * @param request
     * @return
     */
    @Mapping("rpc/paramRpc")
    public Result rpcParam(@Body PersonProto.GetAddressBookRequest request) {
        PersonProto.AddressBook addressBook = blockingStub.getAddressBook(request);
        return Result.succeed(addressBook);
    }

    @Mapping("rpc/hello2")
    public Result rpcHello2(@Body PersonProto.Person request) {

        StreamObserver<PersonProto.AddPeopleResponse> streamObserver = new StreamObserver<>() {
            @Override
            public void onNext(PersonProto.AddPeopleResponse addPeopleResponse) {
                int count = addPeopleResponse.getCount();
                log.info("count:{}", count);
            }

            @Override
            public void onError(Throwable throwable) {
                log.info("error:{}", throwable.getMessage());
            }

            @Override
            public void onCompleted() {
                log.info("completed");

            }
        };
        StreamObserver<PersonProto.Person> observer = asyncStub.addPeople(streamObserver);
        observer.onNext(PersonProto.Person.newBuilder().setId(1).setName(request.getName()).build());
        observer.onNext(PersonProto.Person.newBuilder().setId(2).setName(request.getName()).build());
        observer.onCompleted();

        log.info("test hello2");
        return Result.succeed(GrpcMessageUtil.toJson(request));
    }

    @Mapping("rpc/hello3")
    public Result rpcHello3(HashMap<String, Object> name) {

        ArrayList<Object> result = new ArrayList<>();
        StreamObserver<PersonProto.AddressBook> streamObserver = new StreamObserver<>() {

            @Override
            public void onNext(PersonProto.AddressBook addressBook) {
                log.info("addressBook:{}", addressBook);
                result.add(addressBook);
            }

            @Override
            public void onError(Throwable throwable) {
                log.info("error:{}", throwable.getMessage());
            }

            @Override
            public void onCompleted() {
                log.info("completed");
                log.info("result.size:{}", result.size());
            }
        };
        StreamObserver<PersonProto.AddressBook> observer = asyncStub.syncAddressBook(streamObserver);
        for (int i = 0; i < 10; i++) {
            observer.onNext(PersonProto.AddressBook.newBuilder()
                    .addPeople(PersonProto.Person.newBuilder()
                            .setName(RandomUtil.randomString(5))
                            .setId(RandomUtil.randomInt())
                            .build())
                    .build());
        }
        observer.onCompleted();

        log.info("test hello3");
        return Result.succeed(name);
    }

}
